package fst.parsing

import fst.binding.Binding

trait ContextualParsers extends Parsers with MoreCombinators {
  val syntax: Binding
  import syntax._ 
  
  type Context <: ContextCore

  val Context: ContextCompanion
  trait ContextCompanion {
    val empty: Context = apply{name => None}
    def apply(f: String => Option[Name]): Context
  }
  
  trait ContextCore extends (String => Option[Name]) {
    def bind(nameParser: Parser[String]): Parser[(Context, Name)] = (for(name <- nameParser) yield {val n=Name(name); (this(name) = n, n)})
    def bound(nameParser: Parser[String]): Parser[Name]  = (for(name <- nameParser; binder <- lookup(name)) yield binder)
    def lookup(name: String): Parser[Name] = this(name) match {
      case None => failure explain("unbound name: "+name)
      case Some(b) => success(b)
    }
    def in[T](p: Context => Parser[AlsoNominal[T]]): Pair[Context, Name] => Parser[\\[T]] = {case (ctx, n) => p(ctx) ^^ (\\(n, _))}
    
    def update(rawName: String, binder: Name): Context = Context{name => if(name == rawName) Some(binder) else this(name) }
  }
}